package com.seed.core.pojo.seed;

import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryTable;
import com.seed.core.builder.pojo.OnCondition1;
import com.seed.core.builder.pojo.Table1;
import com.seed.util.SeedKit;
import com.seed.util.StrKit;

import java.util.*;
import java.util.stream.Stream;

/**
 * select t.* FROM uaa_role t
 * INNER JOIN uaa_user_role ur
 * 	on t.id=ur.role_id
 * 	and ur.id='57310005058000122'
 * 	and t.name like '%软%'
 * 	and ur.user_id = '57272664762000101'
 * 	and '张三'='张三';
 *
 * select t.* from uaa_user t WHERE t.organization_id='57191292263000158' and t.name='张三';
 *
 * select organization.name as `organization.name`, t.* FROM uaa_user t
 * LEFT JOIN uaa_organization as `organization` on `organization`.manager_id=t.id and organization.id='57136949836000170'
 * INNER JOIN uaa_user_role _
 * 	on t.id=_.user_id
 * 	and _.role_id = '57290003449000109'
 * 	and _.id='57310005057000117'
 * 	and t.name='张三'
 * 	and '部门经理' like '%部门%';
 */
public abstract class Relation implements Property {
    protected String targetSeedName;
    protected Seed selfSeed;
    protected Seed targetSeed;
    protected Class<?> selfEntityClass;
    protected Class<?> targetEntityClass;
    protected String selfColumn;
    protected String targetColumn;
    protected String label;
    protected String comment;

    protected Map<String, Object> extra; // 扩展参数

    public abstract Relation clone();

//    public String getCodeColumnName() {
//        if(this.extra == null || this.extra.isEmpty()) return Const.CODE;
//
//        Map.Entry<String, Object> entry = this.extra.entrySet().iterator().next();
//        Object value = entry.getValue();
//        if(value == null) return StrUtil.toUnderlineCase(entry.getKey());
//
//        return StrUtil.toUnderlineCase((CharSequence) entry.getValue());
//    }

//    public Map<String, Object> getColumnAndValues() {
//        Map<String, Object> ret = new HashMap<>();
//        if(this.extra == null) return ret;
//
//        Seed extraSeed = getExtraSeed();
//        for(Map.Entry<String, Object> entry: this.extra.entrySet()) {
//            String columnName = StrUtil.toUnderlineCase(entry.getKey());
//            if (!extraSeed.getColumns().containsKey(columnName)) {
//                ThrowKit.exception("【%s】中不存在列【%s】", extraSeed.getName(), columnName);
//            }
//            ret.put(columnName, entry.getValue());
//        }
//        return ret;
//    }

    public abstract Seed getExtraSeed();

//    public QueryCondition getQueryCondition(String basePath, String cross) {
//        if(this instanceof Habtms) throw new RuntimeException("不支持此方法调用");
//
//        String selfTableAlias = StrKit.selfTableAlias(basePath);
//        String targetTableAlias = StrKit.targetTableAlias(basePath, cross);
//        return getQueryCondition(selfTableAlias, this instanceof HasOnes ? targetTableAlias : selfTableAlias, targetTableAlias);
//    }

    public QueryCondition getQueryCondition(String selfTableAlias, String targetTableAlias) {
        QueryTable selfTable = new QueryTable(selfSeed.getTableName()).as(selfTableAlias);
        QueryTable targetTable = new QueryTable(targetSeed.getTableName()).as(targetTableAlias);
        String inferSelfColumn = inferSelfColumn();
        String inferTargetColumn = inferTargetColumn();

        QueryCondition ret = new QueryColumn(targetTable, inferTargetColumn).eq(new QueryColumn(selfTable, inferSelfColumn));
        for(Map.Entry<String, Object> entry: SeedKit.formatExtra(getExtraSeed(), getExtra()).entrySet()) {
            ret.and(new QueryColumn(selfTable, entry.getKey()).eq(entry.getValue()));
        }

        return ret;
    }

    public OnCondition1 getQueryCondition1(String selfTableAlias, String targetTableAlias) {
        Table1 selfTable = new Table1(selfSeed.getTableName()).as(selfTableAlias);
        Table1 targetTable = new Table1(targetSeed.getTableName()).as(targetTableAlias);
        String inferSelfColumn = inferSelfColumn();
        String inferTargetColumn = inferTargetColumn();

        OnCondition1 on = new OnCondition1(selfTable, inferSelfColumn, targetTable, inferTargetColumn);
        on.setExtra(SeedKit.formatExtra(getExtraSeed(), getExtra()));

        return on;
    }


//    public QueryCondition getQueryCondition(String selfTableAlias, String throughAlias, String targetTableAlias) {
//        QueryTable selfTable = new QueryTable(selfSeed.getTableName()).as(selfTableAlias);
//        QueryTable targetTable = new QueryTable(targetSeed.getTableName()).as(targetTableAlias);
//        String inferSelfColumn = inferSelfColumn();
//        String inferTargetColumn = inferTargetColumn();
//
//        if(condition == null || condition.length == 0) {
//            return new QueryColumn(targetTable, inferTargetColumn).eq(new QueryColumn(selfTable, inferSelfColumn));
//        }
//
//        QueryCondition ret = hasCrossField()
//                ? new QueryColumn(targetTable, inferTargetColumn).eq(new QueryColumn(selfTable, inferSelfColumn))
//                : QueryCondition.createEmpty();
//
//        Map<TableType, Set<String>> columns = getConditionColumns();
//        for(String c: condition) {
//            for(Map.Entry<TableType, Set<String>> entry: columns.entrySet()) {
//                TableType tableType = entry.getKey();
//                String alias = switch (tableType) {
//                    case self -> selfTableAlias;
//                    case target -> targetTableAlias;
//                    case through -> throughAlias;
//                };
//                Set<String> columnNames = entry.getValue();
//                for (String columnName: columnNames) {
//                    String replacement = String.format("`%s`.`%s`", alias, columnName);
//                    c = c.replace(String.format("`%s.%s`", tableType, columnName), replacement);
//                }
//            }
//            ret.and(c);
//        }
//
//        return ret;
//    }

//    public Set<String> getConditionColumnNames(TableType tableType) {
//        return getConditionColumns().get(tableType);
//    }

//    public Map<TableType, Set<String>> getConditionColumns() {
//        if(conditionColumns == null) {
//            conditionColumns = new HashMap<>();
//            if(condition != null) {
//                for(String c: condition) initConditionItem(conditionColumns, c);
//            }
//        }
//
//        return conditionColumns;
//    }

//    public String getSelfColumnName() {
//        if(type == RelationType.code) return null;
//
//        return inferSelfColumn();
//    }

//    public String getSelfColumnName() {
//        if(condition == null) return inferSelfColumn();
//        if(StrUtil.isNotBlank(selfColumn)) return selfColumn;
//        if(StrUtil.isNotBlank(targetColumn)) return inferSelfColumn();
//
//        return null;
//    }

    public Map<String, QueryColumn> getSelfExtraSelects(String basePath) {
        Map<String, QueryColumn> ret = new HashMap<>();

        String selfTableAlias = StrKit.selfTableAlias(basePath);
        QueryTable selfTable = new QueryTable(selfSeed.getTableName()).as(selfTableAlias);

//        if(extraType == ExtraType.code) return put(ret, basePath, selfTable, getCodeColumnName());
//        if(extraType == ExtraType.through && this instanceof BelongsTos) return ret;

        return put(ret, basePath, selfTable, inferSelfColumn());
    }

//    public Map<String, QueryColumn> getSelfExtraSelects(String basePath) {
//        Map<String, QueryColumn> ret = new HashMap<>();
//
//        String selfTableAlias = StrKit.selfTableAlias(basePath);
//        QueryTable selfTable = new QueryTable(selfSeed.getTableName()).as(selfTableAlias);
//
//        if(condition == null || condition.length == 0) return put(ret, basePath, selfTable, inferSelfColumn());
//
//        if(StrUtil.isNotBlank(selfColumn)) put(ret, basePath, selfTable, inferSelfColumn());
//
//        if(StrUtil.isNotBlank(targetColumn)) put(ret, basePath, selfTable, inferSelfColumn());
//
//        Map<TableType, Set<String>> columns = getConditionColumns();
//        Set<String> columnNames = columns.get(TableType.self);
//        if(columnNames != null) {
//            for (String columnName: columnNames) put(ret, basePath, selfTable, columnName);
//        }
//
//        return ret;
//    }

    private static Map<String, QueryColumn> put(Map<String, QueryColumn> ret, String basePath, QueryTable selfTable, String selfColumn) {
        String selfColumnPath = StrKit.concat(basePath, selfColumn);
        String columnAlias = StrUtil.toCamelCase(selfColumnPath);
        ret.putIfAbsent(selfColumnPath, new QueryColumn(selfTable, selfColumn, columnAlias));

        return ret;
    }

    public String targetColumn() {
        return StrUtil.toUnderlineCase(targetColumn);
    }

    public String selfColumn() {
        return StrUtil.toUnderlineCase(selfColumn);
    }

    public String inferSelfColumn() {
        throw new RuntimeException("未实现");
    }

    public String inferTargetColumn() {
        throw new RuntimeException("未实现");
    }

    public String selfField() {
        return StrUtil.toCamelCase(selfColumn);
    }

    public String targetField() {
        return StrUtil.toCamelCase(targetColumn);
    }

//    /**
//     * 是否有关联字段
//     * @return
//     */
//    public boolean hasCrossField() {
//        return condition == null || StrUtil.isNotBlank(selfColumn) || StrUtil.isNotBlank(targetColumn);
//    }

//    protected void initConditionItem(Map<TableType, Set<String>> container, String conditionItem) {
//        List<String> list = StrKit.bracket(conditionItem, '`', '`');
//        for(String item: list) {
//            if(!item.contains(".")) throw new RuntimeException("列必需写成【self.列】或【through.列】或【target.列】的形式");
//
//            String[] ownerAndColumn = StrKit.cutInTwo(item, '.', true);
//            String owner = ownerAndColumn[0];
//            String column = ownerAndColumn[1];
//            if(StrUtil.isBlank(owner)) {
//                throw new RuntimeException("列必需以【self, through, target】任何一个开头");
//            }
//            TableType tableType = TableType.valueOf(owner);
//
//            switch (tableType) {
//                case self -> checkColumn(selfSeed, column);
//                case target -> checkColumn(targetSeed, column);
//                case through -> {
//                    if(this instanceof Habtms habtm) {
//                        checkColumn(habtm.getThroughSeed(), column);
//                    } else if(this instanceof HasOnes) {
//                        checkColumn(targetSeed, column);
//                    } else {
//                        checkColumn(selfSeed, column);
//                    }
//                }
//            }
//
//            Set<String> columnNames = container.get(tableType);
//            if(columnNames == null) columnNames = new HashSet<>();
//            columnNames.add(column);
//            container.put(tableType, columnNames);
//        }
//    }

    public String getTargetSeedName() {
        return targetSeedName;
    }

    public void setTargetSeedName(String targetSeedName) {
        this.targetSeedName = StrUtil.toCamelCase(targetSeedName.replace('-', '_'));
    }

    public Seed selfSeed() {
        return selfSeed;
    }

    public void setSelfSeed(Seed selfSeed) {
        this.selfSeed = selfSeed;
    }

    public Seed targetSeed() {
        return targetSeed;
    }

    public void setTargetSeed(Seed targetSeed) {
        this.targetSeed = targetSeed;
    }

    public Class<?> getSelfEntityClass() {
        return selfEntityClass;
    }

    public void setSelfEntityClass(Class<?> selfEntityClass) {
        this.selfEntityClass = selfEntityClass;
    }

    public Class<?> getTargetEntityClass() {
        return targetEntityClass;
    }

    public void setTargetEntityClass(Class<?> targetEntityClass) {
        this.targetEntityClass = targetEntityClass;
    }

    public String getSelfColumn() {
        return selfColumn;
    }

    public void setSelfColumn(String selfColumn) {
        this.selfColumn = selfColumn;
    }

    public String getTargetColumn() {
        return targetColumn;
    }

    public void setTargetColumn(String targetColumn) {
        this.targetColumn = targetColumn;
    }

//    public String[] getCondition() {
//        return condition;
//    }
//
//    public void setCondition(String[] condition) {
//        if(condition == null) {
//            this.condition = null;
//        } else {
//            condition = Stream.of(condition).filter(StrUtil::isNotBlank).toArray(String[]::new);
//            this.condition = condition.length > 0 ? condition : null;
//        }
//    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public Map<String, Object> getExtra() {
        return extra;
    }

    public void setExtra(Map<String, Object> extra) {
        this.extra = extra;
    }

    public void setExtra(String extra) {
        this.extra = new HashMap<>();
        if(StrUtil.isBlank(extra)) return;

        Stream<String> stream = Arrays.stream(extra.split(","));
        List<String> list = stream.filter(StrUtil::isNotBlank).map(String::trim).distinct().toList();
        for(String item: list) {
            String[] keyValue = item.split("=");
            this.extra.put(keyValue[0].trim(), keyValue.length > 1 ? keyValue[1].trim() : null);
        }
    }
}
